package com.enqualcomm.kids.mvp.map;


import com.amap.api.maps.AMapUtils;
import com.amap.api.maps.model.LatLng;
import com.amap.api.services.core.LatLonPoint;
import com.amap.api.services.route.DrivePath;
import com.amap.api.services.route.DriveRouteResult;
import com.amap.api.services.route.DriveStep;
import com.amap.api.services.route.RouteSearch;
import com.amap.api.services.route.WalkPath;
import com.amap.api.services.route.WalkRouteResult;
import com.amap.api.services.route.WalkStep;
import com.enqualcomm.kids.bean.CalculateResult;
import com.enqualcomm.kids.component.MyApplication;

import java.util.ArrayList;
import java.util.List;

import rx.Observable;
import rx.Subscriber;

/**
 * Created by yinzhiqun on 2015/12/30.
 *
 */
public class AMapCalculateObservable implements Observable.OnSubscribe<CalculateResult> {

    private static final int CALCULATE_METHOD_WALK = 1;
    private static final int CALCULATE_METHOD_DRIVE = 2;

    private static final int WALK_SAMPLING = 3;
    private static final int DRIVE_SAMPLING = 3;

    private static final int BLURRY = 25;

    CalculateResult calculateResult;


    public AMapCalculateObservable(CalculateResult calculateResult) {
        this.calculateResult = calculateResult;
    }

    @Override
    public void call(final Subscriber<? super CalculateResult> subscriber) {
        RouteSearch search = new RouteSearch(MyApplication.getInstance());
        LatLonPoint start = new LatLonPoint(calculateResult.start.latlng.latitude, calculateResult.start.latlng.longitude);
        LatLonPoint end = new LatLonPoint(calculateResult.end.latlng.latitude, calculateResult.end.latlng.longitude);

        if (getCalculateMethod(calculateResult.start.movetype) == CALCULATE_METHOD_WALK) {
            WalkRouteResult walkRouteResult = calculateWalk(start, end, search);
            merge(walkRouteResult, calculateResult);
        } else {
            DriveRouteResult driveRouteResult = calculateDrive(start, end, search);
            merge(driveRouteResult, calculateResult);
        }
        subscriber.onNext(calculateResult);
        subscriber.onCompleted();
    }

    private static WalkRouteResult calculateWalk(LatLonPoint start, LatLonPoint end, RouteSearch search) {
        try {
            RouteSearch.WalkRouteQuery walkRouteQuery = new RouteSearch.WalkRouteQuery(new RouteSearch.FromAndTo(start, end), RouteSearch.WalkDefault);
            return search.calculateWalkRoute(walkRouteQuery);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static DriveRouteResult calculateDrive(LatLonPoint start, LatLonPoint end, RouteSearch search) {//RouteSearch.DrivingDefault
        try {
            RouteSearch.DriveRouteQuery driveRouteQuery = new RouteSearch.DriveRouteQuery(new RouteSearch.FromAndTo(start, end), RouteSearch.DrivingDefault, null, null, null);
            return search.calculateDriveRoute(driveRouteQuery);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    private static void merge(WalkRouteResult walkRouteResult, CalculateResult calculateResult) {
        if (walkRouteResult != null) {
            calculateResult.calculatePoints = new ArrayList<>();
            List<WalkPath> paths = walkRouteResult.getPaths();
            if (paths != null && paths.size() > 0) {

                int loopCount = 0;
                int size1 = paths.get(0).getSteps().size();
                for (int j = 0; j < size1; j++) {
                    WalkStep walkStep = paths.get(0).getSteps().get(j);
                    calculateResult.distance += walkStep.getDistance();

                    int size = walkStep.getPolyline().size();
                    for (int i = 0; i < size; i++) {
                        LatLonPoint latLonPoint = walkStep.getPolyline().get(i);
                        LatLng latLng = new LatLng(latLonPoint.getLatitude(), latLonPoint.getLongitude());

                        loopCount++;
                        if (loopCount % WALK_SAMPLING == 0) {

                            //一定范围内，进行模糊处理
                            if (AMapUtils.calculateLineDistance(calculateResult.start.latlng, latLng) <BLURRY){
                                continue;
                            }else if (AMapUtils.calculateLineDistance(calculateResult.end.latlng, latLng) <BLURRY){
                                continue;
                            }

                            calculateResult.calculatePoints.add(latLng);
                        }
                    }
                }
            }
        }
    }

    private static void merge(DriveRouteResult driveRouteResult, CalculateResult calculateResult) {
        if (driveRouteResult != null) {
            calculateResult.calculatePoints = new ArrayList<>();
            List<DrivePath> paths = driveRouteResult.getPaths();
            if (paths != null && paths.size() > 0) {

                int loopCount = 0;
                int size1 = paths.get(0).getSteps().size();
                for (int j = 0; j < size1; j++) {
                    DriveStep driveStep = paths.get(0).getSteps().get(j);
                    calculateResult.distance += driveStep.getDistance();

                    int size = driveStep.getPolyline().size();
                    for (int i = 0; i < size; i++) {
                        LatLonPoint latLonPoint = driveStep.getPolyline().get(i);
                        LatLng latLng = new LatLng(latLonPoint.getLatitude(), latLonPoint.getLongitude());

                        loopCount++;
                        if (loopCount % DRIVE_SAMPLING == 0) {

                            //一定范围内，进行模糊处理
                            if (AMapUtils.calculateLineDistance(calculateResult.start.latlng, latLng) <BLURRY){
                                continue;
                            }else if (AMapUtils.calculateLineDistance(calculateResult.end.latlng, latLng) <BLURRY){
                                continue;
                            }

                            calculateResult.calculatePoints.add(latLng);
                        }
                    }
                }
            }
        }
    }


    private static int getCalculateMethod(int movetype) {
        int method;
        switch (movetype) {
            case CalculateUtil.MODE_WALK:
                method = CALCULATE_METHOD_WALK;
                break;
            case CalculateUtil.MODE_DRIVE:
                method = CALCULATE_METHOD_DRIVE;
                break;
            default:
                method = CALCULATE_METHOD_WALK;
                break;
        }
        return method;
    }
}
